/**
 * Kamikaze Project JS
 * @author mahny
 */
/**
 * ライブラリの情報等
 */
var KmkzProject = {
	
	name : "Kamikaze Project JS",
	license : "MIT License",
	author : "mahny",
	revision : "9",
	
	/**
	 * このライブラリの情報をポップアップ表示する
	 */
	popupAbout : function() {
		window.alert(ObjectUtils.toString(this));
	}
}

/**
 * オブジェクト操作ユーティリティ
 */
function _ObjectUtils() {
	
	/**
	 * オブジェクト内のフィールドを文字列表現に変換する
	 * @param {Object} obj
	 */
	this.toString = function(obj, separator) {
		var arrPropertyNameList = new Array();
		for ( var item in obj )
		{
			if ( typeof( obj[item] ) != "function" )
			{
				arrPropertyNameList.push( item );
			}
		}
		
		var result = "";
		separator = separator ? separator : ",\n";
		for ( var propertyIndex in arrPropertyNameList )
		{
			var key = arrPropertyNameList[propertyIndex];
			result += key + "=" + obj[key] + separator;
		}
		result = result.substring(0, result.length - separator.length);
		return result;
	}		
}
var ObjectUtils = new _ObjectUtils();

/**
 * 文字操作ユーティリティ
 */
function _StringUtils() {
	
	var PATTERN_ALL = new RegExp(/%(-{0,1})(0{0,1})([0-9]*)([sdx])/);
	var PATTERN_END = new RegExp(/[sdx]/);
	
	/*
	 * [private]書式を解析する
	 * @param {String} formatString
	 * @return {Object} 解析結果オブジェクト
	 */
	var parseFormatString = function(formatString) {
		
		var tmp = formatString.replace(PATTERN_ALL, "$1/$2/$3/$4").split("/");
		var result = {
			isLeft : (tmp[0].length > 0),
			isZeroPadding : (tmp[1].length > 0),
			range : ((tmp[2].length > 0) ? parseInt(tmp[2]) : 0),
			formatChar : tmp[3]
		};
		return result;
	}
	
	/*
	 * [private]指定文字で桁を埋める
	 * @param {String} targetStr 元の文字列
	 * @param {String} paddingStr 桁埋めに使用する文字(1文字のみ)
	 * @param {int} range 桁数
	 * @param {boolean} true:左側を埋める / false:右側を埋める
	 * @return {String} 桁埋めした文字列
	 */
	var padding = function(targetStr, paddingStr, range, isLeft) {
		
		var diff = "";
		for (var i = targetStr.length; i < range; i++) {
			diff += paddingStr;
		}
		var result = isLeft ? targetStr + diff : diff + targetStr;
		return result;
	}
	
	/**
	 * 書式付き文字列による出力をする
	 * @param {String} formatStr 書式文字列
	 * @param {Object} 第2引数以降は代入値
	 */
	this.format = function(formatStr) {
		
		formatStr = formatStr.replace(/%%/g, "%p");
		var beginIndex = formatStr.search(PATTERN_ALL);
		if (beginIndex < 0) {
			return formatStr.replace(/%p/g, "%");
		}
		
		var endIndex = formatStr.search(PATTERN_END) + 1;
		var result = formatStr.substring(0, beginIndex);
		var replaceStr = formatStr.substring(beginIndex, endIndex);
		formatStr = formatStr.substring(endIndex);
		
		for (var i = 1; i < arguments.length; i++) {
			
			var args = String(arguments[i]);
			var parseObject = parseFormatString(replaceStr);
			
			switch (parseObject.formatChar) {
				case "s":
					if (parseObject.range > args.length) {
						if (parseObject.isZeroPadding) {
							args = padding(args, "0", parseObject.range, parseObject.isLeft);
						} else {
							args = padding(args, " ", parseObject.range, parseObject.isLeft);
						}
					}
					break;
				case "d":
//					args = parseInt(args).toString(10);
					if (parseObject.range > args.length) {
						if (parseObject.isZeroPadding) {
							args = padding(args, "0", parseObject.range, parseObject.isLeft);
						} else {
							args = padding(args, " ", parseObject.range, parseObject.isLeft);
						}
					}
					break;
				case "x":
					args = parseInt(args).toString(16);
					if (parseObject.range > args.length) {
						if (parseObject.isZeroPadding) {
							args = padding(args, "0", parseObject.range, parseObject.isLeft);
						} else {
							args = padding(args, " ", parseObject.range, parseObject.isLeft);
						}
					}
					break;
				default :
			}
			
			result += args;
			
			beginIndex = formatStr.search(PATTERN_ALL);
			if (beginIndex < 0) {
				result += formatStr;
				break;
			}
			endIndex = formatStr.search(PATTERN_END) + 1;
			result += formatStr.substring(0, beginIndex);
			replaceStr = formatStr.substring(beginIndex, endIndex);
			formatStr = formatStr.substring(endIndex);
		}
		return result.replace(/%p/g, "%");
	}
	
	/**
	 * 指定した文字列の前後の空白を取り除く
	 * @param {String} org
	 */
	this.trim = function(org) {
		return org.replace(/^\s+|\s+$/g, "");
	}
}
var StringUtils = new _StringUtils();


/**
 * 日付操作ユーティリティ
 */
function _DateUtils() {
	
	var PATTERN_MONTH_L = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
	var PATTERN_MONTH_M = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
	
	var PATTERN_DAY_L = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
	var PATTERN_DAY_M = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
	var PATTERN_DAY_S = ["S", "M", "T", "W", "T", "F", "S"];
	
	var PATTERN_NOON_M = ["AM", "PM"];
	var PATTERN_NOON_S = ["A", "P"];
	
	/**
	 * 書式付き文字列による出力をする
	 * <dl>
	 * 	<dt>y</dt>
	 * 	<dd>西暦。yyyy:4桁(0埋め) / yy:下2桁(0埋め) / y:0埋め無し</dd>
	 * 	<dt>C</dt>
	 * 	<dd>月の英字表記。CC:英字 / C:省略英字</dd>
	 * 	<dt>M</dt>
	 * 	<dd>月。MM:2桁(0埋め) / M:0埋め無し</dd>
	 * 	<dt>d</dt>
	 * 	<dd>日付。dd:2桁(0埋め) / d:0埋め無し</dd>
	 * 	<dt>H</dt>
	 * 	<dd>時間の24時間表記(0～23)。HH:2桁(0埋め) / H:0埋め無し</dd>
	 * 	<dt>h</dt>
	 * 	<dd>時間の12時間表記(0～11)。hh:2桁(0埋め) / h:0埋め無し</dd>
	 * 	<dt>m</dt>
	 * 	<dd>分。mm:2桁(0埋め) / m:0埋め無し</dd>
	 * 	<dt>s</dt>
	 * 	<dd>秒。ss:2桁(0埋め) / s:0埋め無し</dd>
	 * 	<dt>S</dt>
	 * 	<dd>ミリ秒。SSS:3桁(0埋め) / S:0埋め無し</dd>
	 * 	<dt>a</dt>
	 * 	<dd>午前午後。aa:"AM"or"PM" / a:"A"or"P"</dd>
	 * 	<dt>E</dt>
	 * 	<dd>曜日。EEE:英字完全表記 / EE:英字3文字 / E:英字1文字 
	 * </dl>
	 * @param {String} formatStr 書式文字列
	 * @param {Date} date 変換する日付
	 */
	this.format = function(formatStr, date){
		
		if (!formatStr) {
			return formatStr;
		}
		var result = formatStr;
		date = date ? date : new Date();
		
		result = result.replace(/yyyy/g, StringUtils.format("%04d", date.getFullYear()));
		result = result.replace(/yy/g, StringUtils.format("%02d", String(date.getFullYear()).slice(-2)));
		result = result.replace(/y/g, String(date.getFullYear()));
		result = result.replace(/MM/g, StringUtils.format("%02d", date.getMonth() + 1));
		result = result.replace(/M/g, StringUtils.format("%d", date.getMonth() + 1));
		result = result.replace(/dd/g, StringUtils.format("%02d", date.getDate()));
		result = result.replace(/d/g, StringUtils.format("%d", date.getDate()));
		result = result.replace(/HH/g, StringUtils.format("%02d", date.getHours()));
		result = result.replace(/H/g, StringUtils.format("%d", date.getHours()));
		result = result.replace(/hh/g, StringUtils.format("%02d", date.getHours() % 12));
		result = result.replace(/h/g, StringUtils.format("%d", date.getHours() % 12));
		result = result.replace(/mm/g, StringUtils.format("%02d", date.getMinutes()));
		result = result.replace(/m/g, StringUtils.format("%d", date.getMinutes()));
		result = result.replace(/ss/g, StringUtils.format("%02d", date.getSeconds()));
		result = result.replace(/s/g, StringUtils.format("%d", date.getSeconds()));
		result = result.replace(/SSS/g, StringUtils.format("%03d", date.getMilliseconds()));
		result = result.replace(/S/g, StringUtils.format("%d", date.getMilliseconds()));
		
		result = result.replace(/aa/g, StringUtils.format("%s", date.getHours() < 12 ? PATTERN_NOON_M[0] : PATTERN_NOON_M[1] ));
		result = result.replace(/a/g, StringUtils.format("%s", date.getHours() < 12 ? PATTERN_NOON_S[0] : PATTERN_NOON_S[1] ));
		
		result = result.replace(/CC/g, StringUtils.format("%s", PATTERN_MONTH_L[date.getMonth()]));
		result = result.replace(/C/g, StringUtils.format("%s", PATTERN_MONTH_M[date.getMonth()]));
		
		result = result.replace(/EEE/g, StringUtils.format("%s", PATTERN_DAY_L[date.getDay()]));
		result = result.replace(/EE/g, StringUtils.format("%s", PATTERN_DAY_M[date.getDay()]));
		result = result.replace(/E/g, StringUtils.format("%s", PATTERN_DAY_S[date.getDay()]));
		
		return result;
	}
}
var DateUtils = new _DateUtils();
